#include "CTSBuilder.h"
#include <algorithm>

using namespace std;

CTSBuilder::CTSBuilder(std::set<unsigned int> pids, bool bUseTimer) 
: m_nCurrentTsSize(0), m_pids(pids), m_bUseTimer(bUseTimer)
{
}
/** 
   d'tor.
   deletes all TSs lists
 */
CTSBuilder::~CTSBuilder()
{		
	m_pids.clear();
	map<unsigned int, vector<CTS*>*>::iterator iter;
    for (iter=m_mStreams.begin(); iter != m_mStreams.end(); ++iter) {
		std::vector<CTS*>* vec = iter->second;
		for(unsigned int j=0; j<vec->size(); j++)
			delete vec->at(j);
		delete vec;
    }
}


void CTSBuilder::findTS(IESParser* cESParser){

	const char* cBuffer = cESParser->getData();
	int nSize = cESParser->getSize();

	int nPointer = 0;
    // as long as that there is a data in the array 
	while (nSize > 0){ 
		int nReadBytes = _BuildTS(cBuffer + nPointer, nSize);
		// moves the point to the new,unparsed data in the array
		nPointer += nReadBytes;  
		// decreases the size of the number of bytes that are not parsed yet
		nSize -= nReadBytes;  
	}
}

int CTSBuilder::_BuildTS(const char* cBuffer, int nBufferSize){
	//Checks if we have an unfinished TS packet from the last time the data was read from the file
	//if so then adds the new data to the unfinished TS
	if (m_nCurrentTsSize > 0){ 
		int nCopy = min(nBufferSize, 188-m_nCurrentTsSize);
		memcpy(m_sLastTs+m_nCurrentTsSize,cBuffer,nCopy);
      //checks if the previously unfinished TS is finished now,if so adds it to the TS list
		if (m_nCurrentTsSize+ nCopy == 188){  
			_add2List();
		}
		return nCopy;
	}

	int nPointer = 0;
    // searching for the start of the new TS 
	while (cBuffer[nPointer] != 0x47 && nPointer < nBufferSize){  
		nPointer++;
	}
	if (nPointer >= nBufferSize)
		return nBufferSize;

	int nCopy = min(nBufferSize - nPointer, 188); 
	memcpy((char*)m_sLastTs, cBuffer + nPointer, nCopy); 
	// checks if the TS is completed,if so sends it to _add2List() in order to add the TS to TS list
	if (nCopy == 188){  
		_add2List();
	}
	return nPointer + nCopy;
}

void CTSBuilder::_add2List(){
    // creates a new TS,by using CTS c'tor that copies data from m_sLastTs to the newTs
	CTS* newTs = new CTS(m_sLastTs); 
	m_nCurrentTsSize = 0;
    // checks if the TS's PID is relevant by comparing its PID to PIDs that were initiated
	//if it's not relevant deletes the new TS
	if ((m_pids.find(newTs->getPID())) == m_pids.end()){  
		delete newTs;	
		return;
	}

	vector<CTS*>* vec;
    // searches for the relevant TS list 
	map<unsigned int, vector<CTS*>*>::iterator it = m_mStreams.find(newTs->getPID()); 
	if (it ==  m_mStreams.end()){
        // if there are no relevant TS list,then creates a new one 
		vec = new vector<CTS*>(); 
		m_mStreams[newTs->getPID()] = vec; 
	}
	else{
		vec = it->second;
	}
	if (m_bUseTimer)
		m_cTimer.setCurrentPCR(newTs->getPCR());
	// pushes the newly completed TS to the relevant TS list
	vec->push_back(newTs); 
}

std::vector<CTS*>* CTSBuilder::getTs(unsigned int PID){
	if ( m_mStreams.find(PID) ==  m_mStreams.end()){
		return NULL;
	}
	return m_mStreams[PID];
}

